package gUploadFile

import (
	"fmt"
	"gitee.com/zjlsliupei/ghelp"
	"github.com/tidwall/gjson"
	"mime/multipart"
	"path/filepath"
	"strings"
	"time"
)

var (
	beforeSaveFunc []func(FileMeta, gjson.Result) error
	afterSaveFunc  []func(File)
	instance       Upload
)

func init() {
	RegisterBeforeSave(defaultBeforeSave)
}

type Upload interface {
	// SaveUploadFiles 保存http请求中的文件
	SaveUploadFiles([]*multipart.FileHeader, map[string]string) ([]File, error)
	// UploadLocalFile 上传本地文件
	UploadLocalFile(string, map[string]string) (File, error)
	// CopyFile 复制文件, 并自动根据规划生成文件名及文件路径
	CopyFile(string, map[string]string) (File, error)
	// DownloadFile 下载文件
	DownloadFile(string, string) error
}

type File struct {
	Filename string `json:"filename"`
	Filepath string `json:"filepath"`
	// 文件大小,单位为byte
	Size int64 `json:"size"`
	// 扩展名如果文件名为111.JPG, ext为.jpg，自动转换为小写
	Ext         string `json:"ext""`
	RawFilename string `json:"raw_filename"`
}

type FileMeta struct {
	Filename string `json:"filename"`
	// 文件大小,单位为byte
	Size int64 `json:"size"`
	// 扩展名如果文件名为111.JPG, ext为.jpg，自动转换为小写
	Ext string `json:"ext""`
}

// RegisterBeforeSave 保存前hook，如果返回不为nil，则停止后续保存动作
func RegisterBeforeSave(cb func(FileMeta, gjson.Result) error) {
	beforeSaveFunc = append(beforeSaveFunc, cb)
}

// RegisterAfterSave 保存后hook，参数为保存的路径
func RegisterAfterSave(cb func(File)) {
	afterSaveFunc = append(afterSaveFunc, cb)
}

// defaultBeforeSave 默认前置hook，检查文件大小，后辍是否合法
func defaultBeforeSave(file FileMeta, option gjson.Result) error {
	// 校验文件大小
	if option.Get("maxSize").Exists() {
		if file.Size > option.Get("maxSize").Int() {
			return fmt.Errorf("fileSize: %d over maxSize: %d", file.Size, option.Get("maxSize").Int())
		}
	}
	// 校验扩展名白名单，黑名单，白名单检测优先
	if option.Get("allowExt").Exists() {
		allowExt := strings.Split(strings.ToLower(option.Get("allowExt").String()), "|")
		if !ghelp.InArray(strings.ToLower(filepath.Ext(file.Filename)), allowExt) {
			return fmt.Errorf("fileExt: %s is not in allowExt: %s", strings.ToLower(filepath.Ext(file.Filename)), strings.ToLower(option.Get("allowExt").String()))
		}
	} else if option.Get("denyExt").Exists() {
		denyExt := strings.Split(strings.ToLower(option.Get("denyExt").String()), "|")
		if ghelp.InArray(strings.ToLower(filepath.Ext(file.Filename)), denyExt) {
			return fmt.Errorf("fileExt: %s is in denyExt: %s", strings.ToLower(filepath.Ext(file.Filename)), strings.ToLower(option.Get("denyExt").String()))
		}
	}
	return nil
}

// doBeforeSaveFunc 执行前辍动作
func doBeforeSaveFunc(header FileMeta, option gjson.Result) error {
	if len(beforeSaveFunc) < 1 {
		return nil
	}
	for _, v := range beforeSaveFunc {
		if err := v(header, option); err != nil {
			return err
		}
	}
	return nil
}

func generateByGroupPattern(groupPattern string, groupParam map[string]string) string {
	var path string
	// 判断是否存在系统匹配项
	patterns := strings.Split(groupPattern, ";")
	for _, v := range patterns {
		p := strings.Split(v, "::")
		if p[0] == "DATETIME" {
			format := strings.TrimRight(strings.TrimLeft(p[1], "{"), "}")
			path += time.Now().Format(format) + "/"
		} else {
			if v, ok := groupParam[p[0]]; ok {
				path += v + "/"
			}
		}
	}
	return path
}

// Init 初始化
// _type: 文件类型，可选值local:本地, aliyunOss: 阿里云oss
func Init(_type string, option string) error {
	var err error
	if _type == "local" {
		instance, err = NewLocal(option)
		return err
	} else if _type == "aliyunOss" {
		instance, err = NewAliyunOss(option)
		return err
	} else {
		return fmt.Errorf("%s is not support", _type)
	}
}

// GetUploadFile 返回实例
func GetUploadFile() Upload {
	return instance
}
